<?php

class FormAction extends AbstractRenderable
{

  /**
   *
   * @var Menu
   */
  //public $menu;

  /**
   * @var Form
   */
  public $form;

  protected $title;

  protected $action;

  protected $formData = array();

  protected $errors;

  protected $layout = false;

  public function __construct(Form $form)
  {
    global $response;

    $this->form = $form;
  }
/*

  public function getMenu()
  {
    if (is_null($this->menu)) {
      if (($this->action & Form::ACTION_OPTIONS) != $this->action) {
        $this->menu = new Menu();

        if ($this->form->show(Form::ACTION_INDEX)) {
          $this->menu->addItem(new MenuItem('list', array('List', 'index'), $this->form->getRoute()));
        }

        if ($this->form->show(Form::ACTION_CREATE)) {
          $this->menu->addItem(new MenuItem('create', array('Create', 'create'), array($this->form->getRoute(), array('action' => 'create'))));
        }
      }
    }

    return $this->menu;
  }
*/

  public function getName()
  {
    return strtolower(substr(get_class($this), strlen('FormAction_')));
  }

  public function getTitle()
  {
    if (empty($this->title)) {
      return Inflector::titleize($this->getName());
    }

    return $this->title;
  }

  public function setTitle($title)
  {
    $this->title = $title;
  }

  public function getErrors()
  {
    return $this->errors;
  }

  public function execute()
  {
    //
  }

  public function filterDbData(&$row, $action)
  {
    $elements = $this->form->getElements($this->action);

    while ($element = $elements->next()) {
      $element->filterDbData($row, $this->action);
    }
  }

  public function render()
  {
    $data = $this->getIterator();

    $elements = $this->form->getElements($this->action);

    if (s::request()->json()) {
      $data = $data->getAll();

      $_elements = array();
      while ($element = $elements->next()) {
        $_elements[] = array('name' => $element->getName(), 'title' => $element->getTitle());
      }
      $elements = $_elements;
    }

    if (/*! s::request()->ajax() && */! s::request()->json()) {
      $this->set('pk', $this->form->pk);
      $this->set('form', $this->form);
      $this->set('action', $this->action);
      $this->set('action_name', Form::$actionValue[$this->action]);
      $this->set('route', $this->form->getRoute());
      $this->set('action_title', $this->getTitle());
      $this->set('module_title', $this->form->title);
      $this->set('filters', $this->form->getVisibleFilters());
      $this->set('sortable', $this->form->sortable);
    }

    $this->set('data', $data);
    $this->set('elements', $elements);

    return $this->getView()->render();
  }

  public function gateway()
  {
    return $this->form->gateway();
  }

  public function getData()
  {
    return $this->formData;
  }

  public function setData($data)
  {
    $this->formData = & $data;
    return $this;
  }

  public function setDataFromPost()
  {
    $post = s::request()->post();

    $elements = $this->form->getElements($this->action);

    $data = $this->getIterator();

    while ($row = $data->next()) {
      foreach ($this->form->getFilters() as $filter) {
        $filter->setDataFromPost($row, $post, $this->action);
      }

      while ($element = $elements->next()) {
        if ($element instanceof FormElement && $element->getField() == $this->form->pk) {
          continue;
        }

        try {
          $element->setDataFromPost($row, $post, $this->action);
        }
        catch (ValidationException $e) {
          $this->errors = array_merge((array) $this->errors, (array) $e->getErrors());
        }
      }
    }

    if (! empty($this->errors)) {
      throw new ValidationException($this->errors);
    }
  }

  protected function hasPostData()
  {
    return s::request()->method(Request::POST);
  }

  public function getTemplate()
  {
    global $config;

    $template = parent::getTemplate();

    if (empty($template)) {
      $template = $config['views_dir'] . '/form/form_' . $this->getName() . '_view.php';
    }
    elseif (! sy_path_is_absolute($template)) {
      $template = $config['views_dir'] . '/form/form_' . $this->template . '_view.php';
    }

    return $template;
  }

  public function getLayout()
  {
    global $config;

    $layout = parent::getLayout();

    if (is_null($layout)) {
      $layout = $config['views_dir'] . '/form/form_layout.php';
    }

    return $layout;
  }

  public function getIterator()
  {
    $iterator = $this->form->iteratorClass;
    return new $iterator($this->formData, $this->form->viewClass);
  }

  public function executeCallback($callback)
  {
    $elements = $this->form->getElements();

    $errors = array();

    $data = $this->getIterator();

    $args = func_get_args();

    while ($element = $elements->next()) {
      try {
        call_user_func_array(array($element, 'executeCallback'), $args);
      }
      catch (ValidationException $e) {
        $errors = array_merge($errors, (array) $e->getErrors());
      }
    }

    array_unshift($args, $callback);

    while ($row = $data->next()) {
      while ($element = $elements->next()) {
        $args[1] = &$row;

        try {
          call_user_func_array(array($element, 'executeCallback'), $args);
        }
        catch (ValidationException $e) {
          $errors = array_merge($errors, (array) $e->getErrors());
        }
      }
    }

    if (! empty($errors)) {
      throw new ValidationException($errors);
    }
  }

}
